#include "ThreadCache.h"


// 申请内存
void* ThreadCache::Allocate(size_t size)
{
    assert(size <= max_byte);
    size_t alignedSize = Tool::RoundUp(size); // 计算对齐后内存
    size_t index = Tool::Index(alignedSize); // 哈希表中位置

    // 对应FreeList有内存块
    if (!_freeLists[index].Empty()) return _freeLists[index].Pop();
    else return FetchFromCentralCache(index, alignedSize); // 向cc申请内存
}
// 释放内存
void ThreadCache::Deallocate(void* obj, size_t size)
{
    assert(obj && size);
    size_t alignedSize = Tool::RoundUp(size);
    size_t index = Tool::Index(alignedSize);
    _freeLists[index].Push(obj); // 返回的内存块不是按顺序挂载到哈希桶

    // 挂载内存块大于maxsize，将内存块返回cc
    if (_freeLists[index].GetSize() > _freeLists[index].GetMaxSize()) //
        return ListToSpan(_freeLists[index], size);
}

// 从cc中获取内存
void* ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
    // 慢增长 tc每次能从cc申请的内存块数为maxsize和内存块最大申请量的较小值
    //Windows.h中也有一个min，冲突了
#ifdef _WIN32
    size_t batchNum = min(_freeLists[index].GetMaxSize(), Tool::NumMoveSize(size));
#else
    size_t batchNum = std::min(_freeLists[index].GetMaxSize(), Tool::NumMoveSize(size));
#endif

    if (batchNum < Tool::NumMoveSize(size)) _freeLists[index].GetMaxSize()++;

    void* start = nullptr;
    void* end = nullptr;
    size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size); //

    if (actualNum < 1) assert(false);
    else if (actualNum == 1) return start;
    else
    {
        _freeLists[index].PushRange(Tool::NextObj(start), end, actualNum - 1); // 插入(start, end]
        return start;
    }
    return nullptr;
}

// 返回内存块到cc
void ThreadCache::ListToSpan(FreeList& list, size_t size)
{
    void* start = nullptr;
    void* end = nullptr;
    list.PopRange(start, end, list.GetMaxSize()); // 从freelist中删除maxsize个内存块
    CentralCache::GetInstance()->ReleaseListToSpan(start, size); // cc回收内存块 
}
